package com.mobilottery.server;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;

import org.apache.commons.codec.binary.Base64;


/**
 * @author amit, yariv
 * Stores user details
 */
@Entity
@Table(name="Users", uniqueConstraints={@UniqueConstraint(columnNames={"USER_NAME"})})
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="Type", discriminatorType=DiscriminatorType.STRING)
public abstract class User implements Serializable
{
  @Id  @GeneratedValue(strategy=GenerationType.AUTO) private Long id;
  @Column(name="USER_NAME", nullable=false, unique=true) private String userName;
  @Column(name="EMAIL", nullable=false) private String email;
  @Column(name="FIRST_NAME") private String firstName;
  @Column(name="LAST_NAME") private String lastName;
  @Column(name="PASSWORD", nullable=false) private String password;
  @Column(name="CREDIT_CARD_NUMBER", nullable=false) private String creditCardNumber;
  @Column(name="IS_BLOCKED", nullable=false) private boolean isBlocked;
  @Column(name="LAST_LOGIN_DATE") @Temporal(TemporalType.TIMESTAMP) private Date lastLoginDate;

  @OneToMany(mappedBy="user", cascade=CascadeType.PERSIST) private List<GameParticipation> gameParticipations = new ArrayList<GameParticipation>();

    public User() {
        this.userName = this.email = this.firstName = this.lastName = this.password = this.creditCardNumber = "";
        this.isBlocked = false;
        this.lastLoginDate = new Date();
    }

    public User(String userName, String email, String firstName, String lastName, String password, String creditCardNumber,
                boolean isBlocked, Date lastLoginDate) {
        this.userName = userName;
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
        setPasswordText(password);
        this.creditCardNumber = creditCardNumber;
        this.isBlocked = isBlocked;
        this.lastLoginDate = lastLoginDate;
    }

    public User(String userName, String email, String firstName, String lastName, String password, String creditCardNumber, boolean isBlocked) {
        this.userName = userName;
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
        setPasswordText(password);
        this.creditCardNumber = creditCardNumber;
        this.isBlocked = isBlocked;
        this.lastLoginDate = new Date();
    }
    
    public String resetPassword()
    {
    	String newPassword = Long.toHexString((long)(Math.random()*Long.MAX_VALUE));
    	setPasswordText(newPassword);
    	return newPassword;
    }
    
    public static String getPasswordDigest(String userName, String password)
    {
    	String id = userName + password;
        MessageDigest passwordDigest;
		try 
		{
			passwordDigest = MessageDigest.getInstance("MD5");
	    	password = new String(Base64.encodeBase64(passwordDigest.digest(id.getBytes())));    	
		} 
		catch (NoSuchAlgorithmException e) 
		{
			//highly unexpected exception, so we don't want it to be checked, convert to unchecked runtime
			throw new RuntimeException("error encoding password", e);
		}   
		return password;
    }
    

    public String getCreditCardNumber() {
        return creditCardNumber;
    }
    
    /**
     * Retrieves shortened credit card label suitable for public display
     * @return
     */
    @Transient
    public String getCreditCardLabel() {
    	String label = creditCardNumber;
    	if(creditCardNumber!=null && creditCardNumber.length()>4) 
    	{
    		label = creditCardNumber.substring(0, 4)+ "-xx";
    	}
    	else
    	{
    		label = "-";
    	}
    	
        return label;
    }    

    public String getEmail() {
        return email;
    }

    public String getFirstName() {
        return firstName;
    }

    public List<GameParticipation> getGameParticipations() {
        return gameParticipations;
    }

    public Long getId() {
        return id;
    }

    public boolean isBlocked() {
        return isBlocked;
    }

    public Date getLastLoginDate() {
        return lastLoginDate;
    }

    public String getLastName() {
        return lastName;
    }

    public String getPassword() {
        return password;
    }

    public String getUserName() {
        return userName;
    }

    public void setCreditCardNumber(String creditCardNumber) {
        this.creditCardNumber = creditCardNumber;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setGameParticipations(List<GameParticipation> gameParticipations) {
        this.gameParticipations = gameParticipations;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setIsBlocked(boolean isBlocked) {
        this.isBlocked = isBlocked;
    }

    public void setLastLoginDate(Date lastLoginDate) {
        this.lastLoginDate = lastLoginDate;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    protected void setPassword(String password) {
        this.password = password;
    }
    
    @Transient
    public void setPasswordText(String password)
    {
    	setPassword(getPasswordDigest(userName, password));
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }


}
